package com.example.filter;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.utils.Const;
import com.example.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * 用于对请求头中Jwt令牌进行校验的工具，为当前请求添加用户验证信息
 * 并将用户的ID存放在请求对象属性中，方便后续使用
 *
 * 该过滤器的主要作用是验证请求中的JWT（JSON Web Token），并根据验证结果
 * 进行用户身份验证和设置，以便在后续的请求处理中能够获取用户的相关信息。
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    // 注入JwtUtils工具类，该类用于处理JWT相关的操作，如解析JWT、从JWT中提取用户信息等
    @Resource
    JwtUtils utils;

    /**
     * 过滤器的核心处理方法，会在每个请求经过过滤器时被调用一次。
     * 该方法负责验证请求头中的JWT令牌，并进行相应的用户身份验证和设置操作。
     *
     * @param request     HttpServletRequest对象，包含了客户端的请求信息，如请求头、请求参数等。
     * @param response    HttpServletResponse对象，用于设置响应信息，如响应头、响应状态码等。
     * @param filterChain FilterChain对象，用于将请求传递给下一个过滤器或目标资源。
     * @throws ServletException 如果在处理请求或响应时发生Servlet相关的异常。
     * @throws IOException      如果在处理请求或响应时发生I/O错误。
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        // 从请求头中获取名为"Authorization"的字段，该字段通常包含JWT令牌
        String authorization = request.getHeader("Authorization");
        // 使用JwtUtils工具类解析JWT令牌，返回一个DecodedJWT对象，如果解析失败则返回null
        DecodedJWT jwt = utils.resolveJwt(authorization);
        // 如果成功解析了JWT令牌（即jwt不为null）
        if (jwt != null) {
            // 使用JwtUtils工具类将解析后的JWT转换为UserDetails对象，该对象包含了用户的详细信息
            UserDetails user = utils.toUser(jwt);
            // 创建一个UsernamePasswordAuthenticationToken对象，用于表示用户的身份验证信息
            // 这里的第二个参数为null，因为JWT已经包含了用户的身份信息，不需要密码
            // 第三个参数为用户的权限信息，从UserDetails对象中获取
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            // 设置身份验证的详细信息，这里使用WebAuthenticationDetailsSource来构建请求的详细信息
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            // 将身份验证信息设置到当前请求的安全上下文（SecurityContextHolder）中
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // 将用户的ID存放在请求对象的属性中，使用Const.ATTR_USER_ID作为属性名
            // 从JWT中提取用户ID的操作由JwtUtils工具类的toId方法完成
            request.setAttribute(Const.ATTR_USER_ID, utils.toId(jwt));
        }
        // 将请求传递给下一个过滤器或目标资源，继续处理请求
        filterChain.doFilter(request, response);
    }
}